package com.billionsfinance.hessian.core;

import com.caucho.hessian.io.AbstractHessianInput;
import com.caucho.hessian.io.AbstractHessianOutput;
import com.caucho.hessian.io.Hessian2Output;
import com.caucho.hessian.io.HessianInput;
import com.caucho.hessian.server.HessianSkeleton;
import org.apache.commons.lang3.StringUtils;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

/**
 * Hessian请求分发，根据不同的URI转发到相应Hessian服务
 *
 * @ ClassName: HessianServerDispatcherServlet.java
 * @ Author: WeiHui-Z
 * @ Date: 2016/11/23 14:04
 * @ Version: v1.0.0
 */
public class HessianServerDispatcherServlet extends HttpServlet {

	private static final long serialVersionUID = 1L;

	@Override
	protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		throw new ServletException("HessianServiceExporter only supports POST requests");
		//doPost(req,resp);
	}

	@Override
	protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		String accessPath = null;
		try {
			String requestURI = req.getRequestURI();
			accessPath = StringUtils.substringAfterLast(requestURI, "/");
			Class<?> interfaceClass = HessianCacheManager.getHessianServerInterfaceClass(accessPath);
			Class<?> serverClass = HessianCacheManager.getHessianServerClass(accessPath);
			if (interfaceClass == null || serverClass == null) {
				throw new RuntimeException("Access path [" + accessPath + "] is not registered in the server table!");
			}
			this.doHessian(req, resp, interfaceClass, serverClass);
		} catch (Throwable e) {
			e.printStackTrace();
			throw new IOException("Access path [" + accessPath + "] request error:" + e.getMessage(), e);
		}
	}

	/**
	 * 处理Hessian请求
	 *
	 * @param request        req
	 * @param response       res
	 * @param interfaceClass server
	 * @param serverClass    server
	 * @throws Exception ex
	 */
	private void doHessian(HttpServletRequest request, HttpServletResponse response, Class<?> interfaceClass, Class<?> serverClass)
			throws Exception {
		HessianSkeleton hessianSkeleton;
		try {
			hessianSkeleton = new HessianSkeleton(serverClass.newInstance(), interfaceClass);
		} catch (Throwable t) {
			t.printStackTrace();
			throw new Exception("Interface [" + serverClass + "] instance of class Error:" + t.getMessage());
		}
		try {
			response.setContentType("application/x-hessian");
			InputStream is;
			OutputStream os;
			is = request.getInputStream();
			os = response.getOutputStream();
			AbstractHessianInput in;
			AbstractHessianOutput out;
			in = new HessianInput(is);
			out = new Hessian2Output(os);
			hessianSkeleton.invoke(in, out);
		} catch (Throwable t) {
			t.printStackTrace();
			throw new Exception("Interface [" + interfaceClass + "] create hessian object error:" + t.getMessage());
		}
	}

}
